#region Using
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
#endregion

public class PoolManager: MonoSingleton<PoolManager> {
	
	// guarantee this will be always a singleton only - can't use the constructor!
	protected PoolManager() {}
	
	#region Variables
	private List<PoolDescription> pools;
	#endregion

	#region Actor
	protected override void ActorAwake()
	{
		pools = new List<PoolDescription>();
	}
	#endregion
	
	#region Public
	public void AddPool(PoolDescription newPool) {
		if (newPool != null && !IsPoolCreated(newPool.name)) {
			newPool.pool = new Pool(newPool.masterPrefab, newPool.initialPoolSize, newPool.name, newPool.allowRuntimeObjectCreation);
			pools.Add(newPool);
		}
	}

	public void AddPools(PoolDescription[] newPools) {
		if (newPools != null) {
			pools.AddRange(newPools);
			
			for (int i = 0; i < newPools.Length; i++) {
				newPools[i].pool = new Pool(newPools[i].masterPrefab, newPools[i].initialPoolSize, newPools[i].name, newPools[i].allowRuntimeObjectCreation);
			}
		}
	}

	public bool IsPoolCreated(string poolName) {
		for (int i=0; i<pools.Count; i++) {
			if (pools[i].name == poolName) {
				return true;
			}
		}
		return false;
	}

	public GameObject GetObjectFromPool(string poolName) {
		return GetObjectFromPool(poolName, false, null);
	}

	public GameObject GetObjectFromPool(string poolName, bool sendInitMessage) {
		return GetObjectFromPool(poolName, sendInitMessage, null);
	}

	public GameObject GetObjectFromPool(string poolName, GameObject masterPrefab) {
		return GetObjectFromPool(poolName, false, masterPrefab);
	}

	public GameObject GetObjectFromPool(string poolName, bool sendInitMessage, GameObject masterPrefab) {
		GameObject go = null;
		
		for (int i = 0; i < pools.Count; i++) {
			if (pools[i].name == poolName) {
				go = pools[i].pool.GetObject();
				if (sendInitMessage) {
					go.BroadcastMessage("InitObject", SendMessageOptions.DontRequireReceiver);
				}
				return go;
			}
		}
		
		//	If we get here, the pool doesn't exist...
		//	If the masterPrefab is not null, this mean we can create a new Pool for this Prefab.
		if (masterPrefab != null) {
			PoolDescription newPool = new PoolDescription();
			newPool.initialPoolSize = 0;
			newPool.masterPrefab = masterPrefab;
			newPool.name = poolName;
			newPool.pool = new Pool(masterPrefab, 1, poolName, true);
			
			Debug.Log("Pool Instantiate: " + poolName);
			
			pools.Add(newPool);
			
			go = newPool.pool.GetObject();
			go.transform.parent = null;
			if (sendInitMessage) {
				go.BroadcastMessage("InitObject", SendMessageOptions.DontRequireReceiver);
			}
			
			Debug.LogWarning(poolName + " Wasn't created. Please add a PoolDescription specifying the initialPoolSize.");	
			return go;
		}
		return null;
	}

	public void ReleaseObjectFromPool(string poolName, GameObject toReleaseObject) {
		ReleaseObjectFromPool(poolName, toReleaseObject, true);
	}

	public void ReleaseObjectFromPool(string poolName, GameObject toReleaseObject, bool sendMessage) {
		if (toReleaseObject != null && sendMessage) {
			toReleaseObject.BroadcastMessage("ReleaseObject", SendMessageOptions.DontRequireReceiver);
		}
		
		for (int i = 0; i < pools.Count; i++) {
			if (pools[i].name == poolName) {
				pools[i].pool.ReleaseObject(toReleaseObject);
				toReleaseObject.transform.parent = actorTransform;
				return;
			}
		}
		
		Debug.Log("PoolManager::ReleaseObjectFromPool -- Can't find the pool: " + poolName);
	}

	public void RemoveCategory(string category) {
		ArrayList toRemove = new ArrayList();
		for (int i = 0; i < pools.Count; i++) {
			if (pools[i].category == category) {
				toRemove.Add(pools[i]);
			}
		}
		
		for (int i=0; i<toRemove.Count; i++) {
			//	-=TODO=- Delete the (PoolDescription)toRemove[i].pool object and created GameObjects.
			pools.Remove((PoolDescription)toRemove[i]);
		}
		
		// -=TODO=- Call ReleaseObjectFromPool to deactivate object
	}

	public void Reset() {
		for (int i=0; i<pools.Count; i++) {
			pools[i].Destroy();
		}
		pools.Clear();
	}
	#endregion
}
